/**
 * Created by IntelliJ IDEA.
 * User: pip
 * Date: 07.06.11
 * Time: 23:56
 */
package com.octopussy.g3dview {
import away3d.core.base.Mesh;
import away3d.events.MouseEvent3D;
import away3d.materials.Material;
import away3d.materials.ShadingColorMaterial;

import flash.events.EventDispatcher;
import flash.net.URLRequest;
import flash.net.navigateToURL;

import mx.collections.ArrayCollection;
import mx.utils.StringUtil;

import spark.components.Application;


public class ObjectManager extends EventDispatcher {
    private var _objects:Object = {};

    private var _staticMaterial:ShadingColorMaterial;

    private var _highlightedObject:ObjectEntry;
    private var _clickDesired:ObjectEntry;
    private var _hint:Hint;
    private var _app:Application;

    private var _downX:int;
    private var _downY:int;

    public function ObjectManager( config:XML, hint:Hint, app:Application ) {
        _app = app;
        _hint = hint;
        for each( var x:XML in config.node ) {
            const interactable:Boolean = x.@interactable == 'true';
            _objects[x.@name] = new ObjectEntry( x.@name, x.@url, x.@title, x.@desc,
                    uint( x.@color ), interactable, this );
        }

        _staticMaterial = new ShadingColorMaterial( 0x555555 );
        _staticMaterial.specular = 1;
    }

    [Bindable(event="legendChanged")]
    public function get legend():ArrayCollection {
        const result:ArrayCollection = new ArrayCollection();
        for each( var o:ObjectEntry in _objects )
            if ( o.interactable )
                result.addItem( o );

        return result;
    }

    public function registerObject( obj:Mesh ):void {
        const name:String = StringUtil.trim( obj.name );

        const entry:ObjectEntry = _objects[ name ];
        if ( entry != null ) {
            const mat:ShadingColorMaterial = new ShadingColorMaterial( entry.color );
            entry.obj = obj;
            entry.defaultMaterial = mat;
            obj.material = mat;

            if ( entry.interactable ) {
                entry.highlightMaterial = createHighlightMaterial( mat.diffuse );
                obj.useHandCursor = true;
                obj.addOnMouseUp( objectUpHandler );
                obj.addOnMouseDown( objectDownHandler );
                obj.addOnRollOver( objectRollOverHandler );
                obj.addOnRollOut( objectRollOutHandler );
            }

        } else {
            obj.material = _staticMaterial;
        }
    }

    public function highlightObject( name:String, showHint:Boolean = true ):void {
        const entry:ObjectEntry = _objects[ StringUtil.trim( name ) ];
        if ( entry == null )
            return;

        entry.obj.material = entry.highlightMaterial;
        _highlightedObject = entry;

        if ( showHint ) {
            _hint.title.text = entry.title;
            _hint.description.text = entry.description;
            _hint.visible = true;
        }
    }

    public function clearHighlight():void {
        if ( _highlightedObject == null )
            return;

        _highlightedObject.obj.material = _highlightedObject.defaultMaterial;
        _highlightedObject = null;

        _hint.visible = false;
    }

    public function clickObject( name:String ):void {
        const entry:ObjectEntry = _objects[ StringUtil.trim( name ) ];
        if ( entry == null )
            return;

        navigateToURL( new URLRequest( entry.url ) );
    }

    private function createHighlightMaterial( diffuse:uint ):Material {
        return new ShadingColorMaterial( 0xff3333 );
    }

    private function objectDownHandler( e:MouseEvent3D ):void {
        _clickDesired = _highlightedObject;
        _downX = _app.mouseX;
        _downY = _app.mouseY;
    }

    private function objectUpHandler( e:MouseEvent3D ):void {
        const dx:int = _app.mouseX - _downX;
        const dy:int = _app.mouseY - _downY;

        const delta:Number = Math.sqrt( dx * dx + dy * dy );

        if ( _clickDesired && delta < 10 )
            clickObject( _clickDesired.name );

        _clickDesired = null;
    }

    private function objectRollOverHandler( e:MouseEvent3D ):void {
        highlightObject( e.object.name );
    }

    private function objectRollOutHandler( e:MouseEvent3D ):void {
        clearHighlight();
    }
}
}
